/** @file sorter.h
	@brief Geometry batch sorter */

#ifndef G3_BATCH_SORTER_H
#define G3_BATCH_SORTER_H

#include <boost/thread/thread.hpp>
#include <set>

#include "singleton.h"

#include "batch.h"

namespace G3 {

/** @class BATCH_SORT_FUNCTOR
	@brief A functor for batch pointer sorting */
class BATCH_SORT_FUNCTOR {
    public:
        /**
            @brief Sorting functor
            @param[in] a Pointer to the first batch to be compared
            @param[in] b Pointer to the second batch to be compared
            @return True if a < b and false otherwise
        */
        bool operator() (BATCH *a, BATCH *b) const;
};

/** @class BATCH_SORTER_THREAD
	@brief A functor for the batch sorter thread */
class BATCH_SORTER_THREAD {
    public:
        /**
            @brief The functor for the sorter thread
            \todo Optimize for CPU performance
        */
        void operator()();
};

/** @class BATCH_SORTER
	@brief Geometry batch sorter singleton */
class BATCH_SORTER: public G3::SINGLETON<BATCH_SORTER> {
    friend class BATCH_SORTER_THREAD;

    public:
        /**
            @brief Constructor that initializes the members
        */
        BATCH_SORTER ();
        /**
            @brief Deconstructor that clears everything
        */
        ~BATCH_SORTER ();

        /** The list of sorted */
        std::deque<BATCH *> batches;

        /** A mutex for blocking the list of batches */
        boost::mutex mutex_batches;

        /** Is the list sorted ? */
        bool sorted;

        /** Pointer to a log */
        G3::LOG *log;

        /**
            @brief Starts the sorter thread
        */
        void start ();
        /**
            @brief Stops the sorter thread
        */
        void stop ();
        /**
            @brief Checks if the sorter thread is online
            @return True if it is and fals if it is not
        */
        bool isOnline ();

        /**
            @brief Adds a new batch into the list
            @param[in] batch Pointer to the batch to be added
            @return True on success, false on failure
        */
        bool add (BATCH *batch);
        /**
            @brief Removes a batch from the list
            @param[in] batch Pointer to the batch to be removed
            @return True on success, false on failure
        */
        bool remove (BATCH *batch);

        /**
            @brief Dumps the batch sorter into the log
        */
        void dump ();

        /**
            @brief Clears the batches and shuts down the sorter
        */
        void clear ();

        /** The pending add batches list */
        std::set<BATCH *> pending_add;
        /** The pending remove batches list */
        std::set<BATCH *> pending_remove;

    private:
        /** Pointer to the sorter thread */
        boost::thread *thread;
        /** Is the sorter thread online ? */
        bool online;

        /** Mutex for blocking the pending list */
        boost::mutex mutex_add;
        /** Mutex for blocking the pending remove list */
        boost::mutex mutex_remove;

        /** The list of unsorted batches */
        std::deque<BATCH *> unsorted;

        /**
            @brief Updates the batches list by adding the pending batches
        */
        void update_add ();

        /**
            @brief Updates the batches list by removing the pending batches
        */
        void update_remove ();

        /**
            @brief Sorts the batchlist
        */
        void sort ();
};

/** The global batch sorter singleton instance */
extern BATCH_SORTER MainBatchSorter;

}

#endif // G3_BATCH_SORTER_H
